#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/types.h>
#include <pthread.h>
#include <fcntl.h>
#include <termios.h>
#include <sys/ioctl.h>
#include <net/if_arp.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <net/if.h>
#include <ctype.h>

#define RELEASE_DATE "2024_0701"

//tool role
#define SERVER 0
#define CLIENT 1
#define CLIENT_DIRECT 2
#define WLAN_CLIENT 3

//interface
#define UART    0
#define USB     1
#define WLAN    2

//uart param
#define BAUDRATE 1500000
#define DATABITS 8
#define PARTY 'N'
#define STOP '1'
#define SOFTWARE_HANDSHAKE 0
#define HARDWARE_HANDSHAKE 1

//socket param
#define BT_HCI_TOOL_PORT 5001
#define SOCKER_BUFFER_SIZE 1024

#define OK 0
#define ERR -1
#define FALSE 0
#define TRUE 1

#define DOWN_FW_CFG             _IOW('E', 176, int)
#define GET_USB_INFO            _IOR('E', 180, int)

#define WLAN_CMD_MAX_CNT        256
#define TXRX_PARA								SIOCDEVPRIVATE+1

#define ARG_IS(_str) (!strcmp(argv[command_counter], _str))
#define OS_STRCMP(str, _str) (!strcmp(str, _str))

int server_or_client = SERVER;
int interface = USB;
int bt_dev_fd = 0;

char s_baudrate[8];

char* s_hci_command[256];
uint8_t r_hci_command[256];
int r_hci_command_len;
char w_ifname[64];
char *w_command[WLAN_CMD_MAX_CNT];
char hci_event[256];

char dev_path[] = "/dev/aicbt_dev";

char hci_reset[] = { 0x01, 0x03, 0x0c, 0x00 };
char set_filter[] = { 0x01, 0x05, 0x0c, 0x03, 0x02, 0x00, 0x02 };
char scan_on[] = { 0x01, 0x1a, 0x0c, 0x01, 0x03 };
char dut_en[] = { 0x01, 0x03, 0x18, 0x00 };

typedef struct android_wifi_priv_cmd {
	char *buf;
	int used_len;
	int total_len;
} android_wifi_priv_cmd;

enum{
	maxLth_DH1=27,
	maxLth_DH3=138,
	maxLth_DH5=339,
	maxLth_2DH1=54,
	maxLth_2DH3=367,
	maxLth_2DH5=679,
	maxLth_3DH1=83,
	maxLth_3DH3=552,
	maxLth_3DH5=1021,
};

enum{
	_dh1,
	_dh3,
	_dh5,
	_2dh1,
	_2dh3,
	_2dh5,
	_3dh1,
	_3dh3,
	_3dh5,
};

typedef enum{
	bt_start,
	bt_stop,
	ble_start,
	ble_stop,
	tx_tone,
	tx_tonestop,
	bt_reset,
	dut,
	dut_dis_scan,
	get_txpwr,
	set_txpwr,
	set_pwrofst,
} cmd_t;

typedef enum {
	tx,
	rx,
} trx_mode_t;

struct bt_test_args_t{	
	trx_mode_t trx_mode;
	cmd_t cmd;
	int type;
	int pattern;
	int hopping;
	int channel;
	uint8_t is_edr;
	int whitening;
	int tx_pwr;
	int len;
	uint8_t addr[6];
	int le_phy;
	int mod_idx;
	int8_t tx_pwrofst;
}bt_test_args={
	.pattern = 0x00,
	.whitening = 0x01,
	.addr = { 0x0A, 0x1C, 0x6B, 0xC6, 0x96, 0x7E },
	.le_phy = 0x01,
	.tx_pwr = 0x7f,
	.tx_pwrofst = 0,
};

#if 0
#define isblank(c)		((c) == ' ' || (c) == '\t')
#define isascii(c)		(((unsigned char)(c)) <= 0x7F)

static int isdigit(unsigned char c)
{
	return ((c >= '0') && (c <='9'));
}

static int isxdigit(unsigned char c)
{
	if ((c >= '0') && (c <='9'))
		return 1;
	if ((c >= 'a') && (c <='f'))
		return 1;
	if ((c >= 'A') && (c <='F'))
		return 1;
	return 0;
}

static int islower(unsigned char c)
{
	return ((c >= 'a') && (c <='z'));
}

static unsigned char toupper(unsigned char c)
{
	if (islower(c))
		c -= 'a'-'A';
	return c;
}
#endif

void helper() {
	printf(
		"\tUsage:\n"
		"\t\t-s <interface> <params>\n"
		"\t\t\tSelect the tool service:\n"

		"\t\t\t\tex. \"bt_test -s uart 1500000 /dev/ttyS0\" or \"bt_test -s usb\" or \"bt_test -s wlan wlan0\"\n"

		"\t\t-c <hci_cmd> Send an HCI command to the selected interface\n"
		"\t\t-v Display Release Date\n"
		"\n"
		"\tCommands:\n"
		"\t\tbt_start [<trx> <chan> <pkt> ...] = Start Bluetooth tx test\n"
		"\t\t\t<trx>      (man) = tx | rx\n"
		"\t\t\t<chan>     (man) = 0 ~ 78 (hopen=off) | 255 (hopen=on)\n"
		"\t\t\t<pkt>      (man) = dh1 | dh3 | dh5 | 2dh1 | 2dh3 | 2dh5 | 3dh1 | 3dh3 | 3dh5\n"
		"\t\t\t<pattern>  (opt) = pn9 (default) | pn15 | h00 | hff | hf0 | h0f | haa | h55\n"
		"\t\t\t<len>      (opt) = dec value (default: pkt's max length)\n"
		"\t\t\t<whiten>   (opt) = on | off (default)\n"
		"\t\t\t<addr>     (opt) = 0a 1c 6b c6 96 7e (default)\n"

		"\t\tbt_stop [<trx>] = Stop Bluetooth tx test\n"
		"\t\t\t<trx>      (man) = tx | rx\n"

 		"\t\tble_start [<trx> <chan> <pkt> ...] = Start BLE tx test\n"
		"\t\t\t<trx>      (man) = tx | rx\n"
		"\t\t\t<chan>     (man) = 0 ~ 39 (hopen=off) | 255 (hopen=on)\n"
		"\t\t\t<pkt>      (man) = 1m | 2m | s2 | s8\n"
		"\t\t\t<pattern>  (opt) = pn9 (default) | pn15 | h00 | hff | hf0 | h0f | haa | h55\n"
		"\t\t\t<len>      (opt) = dec value (default: 255)\n"

		"\t\tble_stop [<trx>] = Stop BLE tx test\n"
		"\t\t\t<trx>      (man) = tx | rx\n"

		"\t\ttx_tone [<chan> ...] = Start a Single-Carrier Bluetooth test\n"
		"\t\t\t<chan>     (man) = 0 ~ 78\n"
		"\t\t\t<pwr>      (opt) = 0 ~ 7 (default: 0x07)\n"
		"\t\ttx_tonestop = Stop Bluetooth Single-Carrier Test\n"

		"\t\tget_txpwr = Get  tx power\n"
		"\t\tset_txpwr [<pwr>] = Set tx power\n"
		"\t\t\t<pwr>	  (man) = 0 ~ 0x6f (default: 0x6f)\n"

		"\t\tbt_reset = reset BT\n"
		"\t\tbt_dut <1/0> = bt_dut /bt_dut 1 (dut en & scan on) | bt_dut 0 (scan off)\n"
		"\t\tset_pwrofst [<pwrofst>]= Set bt tx power offset\n"
		"\t\t\t<pwrofst>      (man) = -7 ~ 7\n"
	);
}


unsigned int command_strtoul(const char *cp, char **endp, unsigned int base)
{
	unsigned int result = 0, value, is_neg = 0;

	if (*cp == '0') {
		cp++;
		if ((*cp == 'x') && isxdigit(cp[1])) {
			base = 16;
			cp++;
		}
		if (!base) {
			base = 8;
		}
	}
	if (!base) {
		base = 10;
	}
	if (*cp == '-') {
		is_neg = 1;
		cp++;
	}
	while (isxdigit(*cp) && (value = isdigit(*cp) ? *cp - '0' : (islower(*cp) ? toupper(*cp) : *cp) - 'A' + 10) < base) {
		result = result * base + value;
		cp++;
	}
	if (is_neg)
		result = (unsigned int)((int)result * (-1));

	if (endp)
		*endp = (char *)cp;
	return result;
}

int parse_cmd_line(int argc, char **argv){
	int command_number = argc;
	int command_counter = 1;
	int hci_command_counter = 0;
	//int error_command = 0;
	int channel = 0;
	//int len = 0 ;

	while(command_counter < command_number){
		if(!strcmp(argv[command_counter], "-s")){
			if(!(command_number >= 3)){
				printf("error command \r\n");
				return ERR;
			}
			printf("bt_hci_tool server setting\r\n");
			server_or_client = SERVER;
			command_counter++;
			if(!strcmp(argv[command_counter], "usb")){
				printf("use USB\r\n");
				interface = USB;
				return OK;
			}else if(!strcmp(argv[command_counter], "uart")){
				interface = UART;
				if(command_number != 5){
					printf("error command \r\n");
					return ERR;
				}
				command_counter++;
				memcpy(s_baudrate, argv[command_counter], strlen(argv[command_counter]));
				command_counter++;
				memset(dev_path, 0, strlen(dev_path));
				memcpy(dev_path, argv[command_counter], strlen(argv[command_counter]));
				printf("use UART %d %s\r\n", atoi(s_baudrate), dev_path);
				return OK;
			}else if(!strcmp(argv[command_counter], "wlan")){
				interface = WLAN;
				if(command_number != 4){
					printf("error command \r\n");
					return ERR;
				}
				command_counter++;
				memcpy(w_ifname, argv[command_counter], strlen(argv[command_counter]));
				printf("use WLAN %s\r\n", w_ifname);
				return OK;
			}else{
				printf("interface set error\r\n");
				return ERR;
			}
		}else if(!strcmp(argv[command_counter], "-c")){
			server_or_client = CLIENT;
			command_counter++;
			hci_command_counter = 0;
			while(command_counter < command_number){
				s_hci_command[hci_command_counter++] = argv[command_counter];
				command_counter++;
			}
			return OK;
		} else if (!strcmp(argv[command_counter], "-w")) {
			int w_command_counter = 0;
			server_or_client = WLAN_CLIENT;
			if (command_number >= WLAN_CMD_MAX_CNT) {
				printf("too much args\r\n");
				return ERR;
			}
			command_counter++;
			while (command_counter < command_number) {
				w_command[w_command_counter++] = argv[command_counter];
				command_counter++;
			}
			return OK;
		}else if (ARG_IS("-m")){
			// reserved for a variety of chip models
		} else if (ARG_IS("bt_start")){
			server_or_client = CLIENT_DIRECT;
			bt_test_args.cmd = bt_start;
			if (command_number < 5) {
				printf("wrong args\r\n");
				return ERR;
			}
			//parse trx
			if (OS_STRCMP(argv[2], "tx")) {
				bt_test_args.trx_mode = tx;
			} else if (OS_STRCMP(argv[2], "rx")) {
				bt_test_args.trx_mode = rx;
			} else {
				printf("no find tx or rx\r\n");
				return ERR;
			}

			//parse chan and hopping
			channel = command_strtoul(argv[3], NULL, 10);
			if (channel < 0 || (channel > 78 && channel != 255)) {
				printf("wrong channel\r\n");
				return ERR;
			} else {
				bt_test_args.channel = channel;
				if (channel == 255)
					bt_test_args.hopping = TRUE;
				else
					bt_test_args.hopping = FALSE;
			}
			//parse type
			if (OS_STRCMP(argv[4], "dh1")){
				bt_test_args.type = _dh1;
				bt_test_args.len = maxLth_DH1;
				bt_test_args.is_edr = FALSE;
			} else if (OS_STRCMP(argv[4], "dh3")){
				bt_test_args.type = _dh3;
				bt_test_args.len = maxLth_DH3;
				bt_test_args.is_edr = FALSE;
			} else if (OS_STRCMP(argv[4], "dh5")){
				bt_test_args.type = _dh5;
				bt_test_args.len = maxLth_DH5;
				bt_test_args.is_edr = FALSE;
			} else if (OS_STRCMP(argv[4], "2dh1")){
				bt_test_args.type = _2dh1;
				bt_test_args.len = maxLth_2DH1;
				bt_test_args.is_edr = TRUE;
			} else if (OS_STRCMP(argv[4], "2dh3")){
				bt_test_args.type = _2dh3;
				bt_test_args.len = maxLth_2DH3;
				bt_test_args.is_edr = TRUE;
			} else if (OS_STRCMP(argv[4], "2dh5")){
				bt_test_args.type = _2dh5;
				bt_test_args.len = maxLth_2DH5;
				bt_test_args.is_edr = TRUE;
			} else if (OS_STRCMP(argv[4], "3dh1")){
				bt_test_args.type = _3dh1;
				bt_test_args.len = maxLth_3DH1;
				bt_test_args.is_edr = TRUE;
			} else if (OS_STRCMP(argv[4], "3dh3")){
				bt_test_args.type = _3dh3;
				bt_test_args.len = maxLth_3DH3;
				bt_test_args.is_edr = TRUE;
			} else if (OS_STRCMP(argv[4], "3dh5")){
				bt_test_args.type = _3dh5;
				bt_test_args.len = maxLth_3DH5;
				bt_test_args.is_edr = TRUE;
			} else {
				printf("wrong type\r\n");
				return ERR;
			}
			//parse pattern
			if (command_number > 5) {
				if (OS_STRCMP(argv[5], "pn9")){
					bt_test_args.pattern =  0x00;
				} else if (OS_STRCMP(argv[5], "hf0")){
					bt_test_args.pattern = 0x01;
				} else if (OS_STRCMP(argv[5], "haa")){
					bt_test_args.pattern = 0x02;
				} else if (OS_STRCMP(argv[5], "pn15")){
					bt_test_args.pattern = 0x03;
				} else if (OS_STRCMP(argv[5], "hff")){
					bt_test_args.pattern = 0x04;
				} else if (OS_STRCMP(argv[5], "h00")){
					bt_test_args.pattern = 0x05;
				} else if (OS_STRCMP(argv[5], "h0f")){
					bt_test_args.pattern = 0x06;
				} else if (OS_STRCMP(argv[5], "h55")){
					bt_test_args.pattern = 0x07;
				} else {
					printf("wrong pattern type\r\n");
					return ERR;
				}

			//parse pkt len
			if (command_number > 6) {
				bt_test_args.len = command_strtoul(argv[6], NULL, 10);
			}

			}
			//parse whitening
			if (command_number > 7) {
				if (OS_STRCMP(argv[7], "on")){
					bt_test_args.whitening =  0x00;
				} else if (OS_STRCMP(argv[7], "off")){
					bt_test_args.whitening = 0x01;
				} else {
					printf("wrong whitening args, use on/off\r\n");
					return ERR;
				}
			}
			//parse mac addr
			if (command_number > 8) {
				if (command_number < 14) {
					printf("wrong mac addr eg: 0a 1c 6b c6 96 7e\r\n");
					return ERR;
				}
			bt_test_args.addr[0] = command_strtoul(argv[8], NULL, 16);
			bt_test_args.addr[1] = command_strtoul(argv[9], NULL, 16);
			bt_test_args.addr[2] = command_strtoul(argv[10], NULL, 16);
			bt_test_args.addr[3] = command_strtoul(argv[11], NULL, 16);
			bt_test_args.addr[4] = command_strtoul(argv[12], NULL, 16);
			bt_test_args.addr[5] = command_strtoul(argv[13], NULL, 16);
			}
			return OK;
		} else if (ARG_IS("bt_stop")){
			server_or_client = CLIENT_DIRECT;
			bt_test_args.cmd = bt_stop;
			if (command_number < 3) {
				printf("wrong args\r\n");
				return ERR;
			}
			//parse trx
			if (OS_STRCMP(argv[2], "tx")) {
				bt_test_args.trx_mode = tx;
			} else if (OS_STRCMP(argv[2], "rx")) {
				bt_test_args.trx_mode = rx;
			} else {
				printf("no find tx or rx\r\n");
				return ERR;
			}
			return OK;
		} else if (ARG_IS("ble_start")){
			server_or_client = CLIENT_DIRECT;
			bt_test_args.cmd = ble_start;
			if (command_number < 5) {
				printf("wrong args\r\n");
				return ERR;
			}
			//parse trx
			if (OS_STRCMP(argv[2], "tx")) {
				bt_test_args.trx_mode = tx;
			} else if (OS_STRCMP(argv[2], "rx")) {
				bt_test_args.trx_mode = rx;
				bt_test_args.mod_idx = 0;//modulation index fix to 0
			} else {
				printf("no find tx or rx\r\n");
				return ERR;
			}

			//parse chan and hopping
			channel = command_strtoul(argv[3], NULL, 10);
			if (channel < 0 || (channel > 39 && channel != 255)) {
				printf("wrong channel\r\n");
				return ERR;
			} else {
				bt_test_args.channel = channel;
				if (channel == 255)
					bt_test_args.hopping = TRUE;
				else
					bt_test_args.hopping = FALSE;
			}
			//parse le phy
			if (OS_STRCMP(argv[4], "1m")){
				bt_test_args.le_phy = 0x01;
			} else if (OS_STRCMP(argv[4], "2m")){
				bt_test_args.le_phy = 0x02;
			} else if (OS_STRCMP(argv[4], "s8")){
				bt_test_args.le_phy = 0x03;
			} else if (OS_STRCMP(argv[4], "s2")){
				if (bt_test_args.trx_mode == tx){
						bt_test_args.le_phy = 0x04;
				} else {
						bt_test_args.le_phy = 0x03;
				}

			} else {
				printf("wrong type\r\n");
				return ERR;
			}
			//parse pattern
			if (command_number > 5) {
				if (OS_STRCMP(argv[5], "pn9")){
					bt_test_args.pattern =  0x00;
				} else if (OS_STRCMP(argv[5], "hf0")){
					bt_test_args.pattern = 0x01;
				} else if (OS_STRCMP(argv[5], "haa")){
					bt_test_args.pattern = 0x02;
				} else if (OS_STRCMP(argv[5], "pn15")){
					bt_test_args.pattern = 0x03;
				} else if (OS_STRCMP(argv[5], "hff")){
					bt_test_args.pattern = 0x04;
				} else if (OS_STRCMP(argv[5], "h00")){
					bt_test_args.pattern = 0x05;
				} else if (OS_STRCMP(argv[5], "h0f")){
					bt_test_args.pattern = 0x06;
				} else if (OS_STRCMP(argv[5], "h55")){
					bt_test_args.pattern = 0x07;
				} else {
					printf("wrong pattern type\r\n");
					return ERR;
				}
			}
			//parse pkt len
			bt_test_args.len = 255;
			if (command_number > 6) {
				bt_test_args.len = command_strtoul(argv[6], NULL, 10);
				if (bt_test_args.len < 1 || bt_test_args.len > 255) {
					printf("len limit 1~255 (default: 255)\r\n");
					}
			}

			return OK;
		} else if (ARG_IS("ble_stop")){
			server_or_client = CLIENT_DIRECT;
			bt_test_args.cmd = ble_stop;
			if (command_number < 3) {
				printf("wrong args\r\n");
				return ERR;
			}
			//parse trx
			if (OS_STRCMP(argv[2], "tx")) {
				bt_test_args.trx_mode = tx;
			} else if (OS_STRCMP(argv[2], "rx")) {
				bt_test_args.trx_mode = rx;
			} else {
				printf("no find tx or rx\r\n");
				return ERR;
			}
			return OK;
		} else if (ARG_IS("tx_tone")){
			server_or_client = CLIENT_DIRECT;
			bt_test_args.cmd = tx_tone;
			if (command_number < 3) {
				printf("wrong args\r\n");
				return ERR;
			}
			//parse chan
			channel = command_strtoul(argv[2], NULL, 10);
			if (channel < 0 || (channel > 78)) {
				printf("wrong channel\r\n");
				return ERR;
			} else {
				bt_test_args.channel = channel;
			}
			//parse tx pwr
			bt_test_args.tx_pwr = 7;
			if (command_number > 3) {
				bt_test_args.tx_pwr = command_strtoul(argv[3], NULL, 16);
				if (bt_test_args.tx_pwr < 0 || bt_test_args.tx_pwr > 7) {
					printf("pwr limit 0~7 (default: 07)\r\n");
					bt_test_args.tx_pwr = 7;
				}
			}
			return OK;
		} else if (ARG_IS("tx_tonestop")){
			server_or_client = CLIENT_DIRECT;
			bt_test_args.cmd = tx_tonestop;
			return OK;
		} else if (ARG_IS("bt_reset")){
			server_or_client = CLIENT_DIRECT;
			bt_test_args.cmd = bt_reset;
			return OK;
		} else if (ARG_IS("bt_dut")){
			server_or_client = CLIENT_DIRECT;
			if (command_number > 2 && !(command_strtoul(argv[2], NULL, 10)))
				bt_test_args.cmd = dut_dis_scan;
			else
				bt_test_args.cmd = dut;
			return OK;
		} else if (ARG_IS("get_txpwr")){
			server_or_client = CLIENT_DIRECT;
			bt_test_args.cmd = get_txpwr;
			return OK;
		} else if (ARG_IS("set_txpwr")){
			server_or_client = CLIENT_DIRECT;
			bt_test_args.cmd = set_txpwr;
			if (command_number < 2) {
				printf("wrong args\r\n");
				return ERR;
			}
			//parse tx pwr
			bt_test_args.tx_pwr = 0x6f;
			if (command_number > 2) {
				bt_test_args.tx_pwr = command_strtoul(argv[2], NULL, 16);
				if (bt_test_args.tx_pwr < 0 || bt_test_args.tx_pwr > 0x7f) {
					printf("pwr limit 0~0x7f (default: 0x6f)\r\n");
					bt_test_args.tx_pwr = 0x6f;
				}
			}
			return OK;
		} else if (ARG_IS("set_pwrofst")){
			server_or_client = CLIENT_DIRECT;
			bt_test_args.cmd = set_pwrofst;
			if (command_number < 2) {
				printf("wrong args\r\n");
				return ERR;
			}
			//parse tx pwrofst
			bt_test_args.tx_pwrofst = 0x0;
			if (command_number > 2) {
				bt_test_args.tx_pwrofst = command_strtoul(argv[2], NULL, 10);
				printf("txpwrofst %d\n", bt_test_args.tx_pwrofst);
				if (bt_test_args.tx_pwrofst < -7 || bt_test_args.tx_pwrofst > 7) {
					printf("pwrofst limit -7 ~ 7\r\n");
					if (bt_test_args.tx_pwrofst > 7) {
						bt_test_args.tx_pwrofst = 7;
					} else if (bt_test_args.tx_pwrofst < -7) {
						bt_test_args.tx_pwrofst = -7;
					}
				}
			}
			return OK;
		} else if (ARG_IS("-v")){
			printf("bt_test %s\n", RELEASE_DATE);
			return ERR;
		} else {
			if (strcmp(argv[1], "-h") != 0) {
				printf("unknow command %s \r\n", argv[command_counter]);
			}
			helper();
			return ERR;
		}

		command_counter++;
	}

	helper();
	return ERR;

}

void uart_set_options(int baudrate, int databits,
    char parity, char stop, int softwareHandshake, int hardwareHandshake)
{
    struct termios newtio;
    if (tcgetattr(bt_dev_fd, &newtio)!=0)
    {
    printf("tcgetattr() 3 failed \n");
    }

    speed_t _baud=0;
    printf("set baudrate:%d\n", baudrate);

    switch (baudrate)
    {
    #ifdef B0
    case      0: _baud=B0;     break;
    #endif
    #ifdef B50
    case     50: _baud=B50;    break;
    #endif
    #ifdef B75
    case     75: _baud=B75;    break;
    #endif
    #ifdef B110
    case    110: _baud=B110;   break;
    #endif
    #ifdef B134
    case    134: _baud=B134;   break;
    #endif
    #ifdef B150
    case    150: _baud=B150;   break;
    #endif
    #ifdef B200
    case    200: _baud=B200;   break;
    #endif
    #ifdef B300
    case    300: _baud=B300;   break;
    #endif
    #ifdef B600
    case    600: _baud=B600;   break;
    #endif
    #ifdef B1200
    case   1200: _baud=B1200;  break;
    #endif
    #ifdef B1800
    case   1800: _baud=B1800;  break;
    #endif
    #ifdef B2400
    case   2400: _baud=B2400;  break;
    #endif
    #ifdef B4800
    case   4800: _baud=B4800;  break;
    #endif
    #ifdef B7200
    case   7200: _baud=B7200;  break;
    #endif
    #ifdef B9600
    case   9600: _baud=B9600;  break;
    #endif
    #ifdef B14400
    case  14400: _baud=B14400; break;
    #endif
    #ifdef B19200
    case  19200: _baud=B19200; break;
    #endif
    #ifdef B28800
    case  28800: _baud=B28800; break;
    #endif
    #ifdef B38400
    case  38400: _baud=B38400; break;
    #endif
    #ifdef B57600
    case  57600: _baud=B57600; break;
    #endif
    #ifdef B76800
    case  76800: _baud=B76800; break;
    #endif
    #ifdef B115200
    case 115200: _baud=B115200; break;
    #endif
    #ifdef B128000
    case 128000: _baud=B128000; break;
    #endif
    #ifdef B230400
    case 230400: _baud=B230400; break;
    #endif
    #ifdef B460800
    case 460800: _baud=B460800; break;
    #endif
    #ifdef B576000
    case 576000: _baud=B576000; break;
    #endif
    #ifdef B921600
    case 921600: _baud=B921600; break;
    #endif
    #ifdef B1500000
    case 1500000: _baud=B1500000; break;
    #endif
    #ifdef B2000000
    case 2000000: _baud=B2000000; break;
    #endif

    default:
        break;
    }
    cfsetospeed(&newtio, (speed_t)_baud);
    cfsetispeed(&newtio, (speed_t)_baud);

    /* We generate mark and space parity ourself. */
    if (databits == 7 && (parity=='M' || parity == 'S'))
    {
        databits = 8;
    }
    switch (databits)
    {
    case 5:
        newtio.c_cflag = (newtio.c_cflag & ~CSIZE) | CS5;
        break;
    case 6:
        newtio.c_cflag = (newtio.c_cflag & ~CSIZE) | CS6;
        break;
    case 7:
        newtio.c_cflag = (newtio.c_cflag & ~CSIZE) | CS7;
        break;
    case 8:
    default:
        newtio.c_cflag = (newtio.c_cflag & ~CSIZE) | CS8;
        break;
    }
    newtio.c_cflag |= CLOCAL | CREAD;

    //parity
    newtio.c_cflag &= ~(PARENB | PARODD);
    if (parity == 'E')
    {
        newtio.c_cflag |= PARENB;
    }
    else if (parity== 'O')
    {
        newtio.c_cflag |= (PARENB | PARODD);
    }

    //hardware handshake
    newtio.c_cflag &= ~CRTSCTS;

    //stopbits
    if (stop=='2')
    {
        newtio.c_cflag |= CSTOPB;
    }
    else
    {
        newtio.c_cflag &= ~CSTOPB;
    }

    newtio.c_iflag=IGNBRK;

    //software handshake
    if (softwareHandshake)
    {
        newtio.c_iflag |= IXON | IXOFF;
    }
    else
    {
        newtio.c_iflag &= ~(IXON|IXOFF|IXANY);
    }

    newtio.c_lflag=0;
    newtio.c_oflag=0;

    //   newtio.c_cc[VTIME]=1;
    //   newtio.c_cc[VMIN]=60;

    if (tcsetattr(bt_dev_fd, TCSANOW, &newtio)!=0)
    {
        printf("tcsetattr() 1 failed \n");
    }

    if (tcgetattr(bt_dev_fd, &newtio)!=0)
    {
        printf("tcsetattr() 4 failed \n");
    }

    //hardware handshake
    if (hardwareHandshake)
    {
        newtio.c_cflag |= CRTSCTS;
    }
    else
    {
        newtio.c_cflag &= ~CRTSCTS;
    }

    if (tcsetattr(bt_dev_fd, TCSANOW, &newtio)!=0)
    {
        printf("tcsetattr() 2 failed \n");
    }
}


unsigned char atoh(char* s_data){
    unsigned char ret_value;
    char temp_value = 0;

    //h
    if(s_data[0] >= 48 && s_data[0] <= 57){
        temp_value = s_data[0] - 48;
    }else if(s_data[0] >= 65 && s_data[0] <= 70){
        temp_value = (s_data[0] - 65) + 10;
    }else if(s_data[0] >= 97 && s_data[0] <= 102){
        temp_value = (s_data[0] - 97) + 10;
    }

    ret_value = temp_value;
    ret_value = ret_value << 4;
    //printf("atoh1: ret_value:%x\r\n", ret_value);
    //l
    if(s_data[1] >= 48 && s_data[1] <= 57){
        temp_value = s_data[1] - 48;
    }else if(s_data[1] >= 65 && s_data[1] <= 70){
        temp_value = (s_data[1] - 65) + 10;
    }else if(s_data[1] >= 97 && s_data[1] <= 102){
        temp_value = (s_data[1] - 97) + 10;
    }

    ret_value |= temp_value;
    //printf("atoh2: ret_value:%x\r\n", ret_value);

    return ret_value;

}

int send_to_server(unsigned char* buffer, int len){
    int client_socket;
    struct sockaddr_in serverAddr;
    //unsigned long long package_totel_counter = 0;

    if((client_socket = socket(AF_INET, SOCK_STREAM, 0)) < 0){
        return ERR;
    }

    serverAddr.sin_family = AF_INET;
    serverAddr.sin_port = htons(BT_HCI_TOOL_PORT);
    serverAddr.sin_addr.s_addr = inet_addr("127.0.0.1");

    if(connect(client_socket, (struct sockaddr *)&serverAddr, sizeof(serverAddr)) < 0){
        return ERR;
    }

    send(client_socket, buffer, len, 0);
    return OK;
}

void send_hci_command(){
    int i = 0;
    int command_len = 0;
    unsigned char buffer[SOCKER_BUFFER_SIZE];

//    printf("send hci command: \r\n");

    for(i = 0;i < 256; i++){
        if(s_hci_command[i] == NULL){
            command_len = i;
            break;
        }

        buffer[i] = atoh(s_hci_command[i]);
//        printf("%02X ", buffer[i]);
    }

    send_to_server(buffer, i);

//    printf("\r\n");
}

void send_raw_hci_command(){
	if (bt_test_args.cmd == bt_stop && bt_test_args.trx_mode == tx){
		r_hci_command[r_hci_command_len++] = 0x01;
		r_hci_command[r_hci_command_len++] = 0x0C;
		r_hci_command[r_hci_command_len++] = 0x18;
		r_hci_command[r_hci_command_len++] = 0x01;
		r_hci_command[r_hci_command_len++] = 0x00;
	} else if (bt_test_args.cmd == bt_stop && bt_test_args.trx_mode == rx){
		r_hci_command[r_hci_command_len++] = 0x01;
		r_hci_command[r_hci_command_len++] = 0x0C;
		r_hci_command[r_hci_command_len++] = 0x18;
		r_hci_command[r_hci_command_len++] = 0x01;
		r_hci_command[r_hci_command_len++] = 0x01;
	} else if ((bt_test_args.cmd == ble_stop && bt_test_args.trx_mode == tx)
		|| bt_test_args.cmd == bt_reset){
		r_hci_command[r_hci_command_len++] = 0x01;
		r_hci_command[r_hci_command_len++] = 0x03;
		r_hci_command[r_hci_command_len++] = 0x0C;
		r_hci_command[r_hci_command_len++] = 0x00;
	} else if (bt_test_args.cmd == ble_stop && bt_test_args.trx_mode == rx){
		r_hci_command[r_hci_command_len++] = 0x01;
		r_hci_command[r_hci_command_len++] = 0x1F;
		r_hci_command[r_hci_command_len++] = 0x20;
		r_hci_command[r_hci_command_len++] = 0x00;
	} else if (bt_test_args.cmd == tx_tonestop){
		r_hci_command[r_hci_command_len++] = 0x01;
		r_hci_command[r_hci_command_len++] = 0x0C;
		r_hci_command[r_hci_command_len++] = 0x18;
		r_hci_command[r_hci_command_len++] = 0x01;
		r_hci_command[r_hci_command_len++] = 0x02;
	} else if (bt_test_args.cmd == bt_start){
		if (bt_test_args.trx_mode == tx){
			r_hci_command[r_hci_command_len++] = 0x01;
			r_hci_command[r_hci_command_len++] = 0x06;
			r_hci_command[r_hci_command_len++] = 0x18;
			r_hci_command[r_hci_command_len++] = 0x0E;
		} else {
			r_hci_command[r_hci_command_len++] = 0x01;
			r_hci_command[r_hci_command_len++] = 0x0B;
			r_hci_command[r_hci_command_len++] = 0x18;
			r_hci_command[r_hci_command_len++] = 0x0D;
		}
		switch (bt_test_args.type){
			case _dh1:
				r_hci_command[r_hci_command_len++] = 0x04;
				break;
			case _dh3:
				r_hci_command[r_hci_command_len++] = 0x0B;
				break;
			case _dh5:
				r_hci_command[r_hci_command_len++] = 0x0F;
				break;
			case _2dh1:
				r_hci_command[r_hci_command_len++] = 0x04;
				break;
			case _2dh3:
				r_hci_command[r_hci_command_len++] = 0x0A;
				break;
			case _2dh5:
				r_hci_command[r_hci_command_len++] = 0x0E;
				break;
			case _3dh1:
				r_hci_command[r_hci_command_len++] = 0x08;
				break;
			case _3dh3:
				r_hci_command[r_hci_command_len++] = 0x0B;
				break;
			case _3dh5:
				r_hci_command[r_hci_command_len++] = 0x0F;
				break;
			default:
				break;
		}
		r_hci_command[r_hci_command_len++] = bt_test_args.pattern;
		if (bt_test_args.trx_mode == tx){
			r_hci_command[r_hci_command_len++] = bt_test_args.hopping;
		}
		r_hci_command[r_hci_command_len++] = bt_test_args.channel;
		r_hci_command[r_hci_command_len++] = bt_test_args.is_edr;
		if (bt_test_args.trx_mode == tx){
			r_hci_command[r_hci_command_len++] = bt_test_args.whitening;
			r_hci_command[r_hci_command_len++] = (bt_test_args.len & 0xFF);
			r_hci_command[r_hci_command_len++] = ((bt_test_args.len >> 8) & 0xFF);
			r_hci_command[r_hci_command_len++] = bt_test_args.addr[5];
			r_hci_command[r_hci_command_len++] = bt_test_args.addr[4];
			r_hci_command[r_hci_command_len++] = bt_test_args.addr[3];
			r_hci_command[r_hci_command_len++] = bt_test_args.addr[2];
			r_hci_command[r_hci_command_len++] = bt_test_args.addr[1];
			r_hci_command[r_hci_command_len++] = bt_test_args.addr[0];
		} else {
			r_hci_command[r_hci_command_len++] = (bt_test_args.len & 0xFF);
			r_hci_command[r_hci_command_len++] = ((bt_test_args.len >> 8) & 0xFF);
			r_hci_command[r_hci_command_len++] = bt_test_args.whitening;
			r_hci_command[r_hci_command_len++] = bt_test_args.addr[5];
			r_hci_command[r_hci_command_len++] = bt_test_args.addr[4];
			r_hci_command[r_hci_command_len++] = bt_test_args.addr[3];
			r_hci_command[r_hci_command_len++] = bt_test_args.addr[2];
			r_hci_command[r_hci_command_len++] = bt_test_args.addr[1];
			r_hci_command[r_hci_command_len++] = bt_test_args.addr[0];
		}
	}else if (bt_test_args.cmd == ble_start && bt_test_args.trx_mode == tx){
		r_hci_command[r_hci_command_len++] = 0x01;
		r_hci_command[r_hci_command_len++] = 0x34;
		r_hci_command[r_hci_command_len++] = 0x20;
		r_hci_command[r_hci_command_len++] = 0x04;
		r_hci_command[r_hci_command_len++] = bt_test_args.channel;
		r_hci_command[r_hci_command_len++] = (bt_test_args.len & 0xFF);
		r_hci_command[r_hci_command_len++] = bt_test_args.pattern;
		r_hci_command[r_hci_command_len++] = bt_test_args.le_phy;
	} else if (bt_test_args.cmd == ble_start && bt_test_args.trx_mode == rx){
		r_hci_command[r_hci_command_len++] = 0x01;
		r_hci_command[r_hci_command_len++] = 0x33;
		r_hci_command[r_hci_command_len++] = 0x20;
		r_hci_command[r_hci_command_len++] = 0x03;
		r_hci_command[r_hci_command_len++] = bt_test_args.channel;
		r_hci_command[r_hci_command_len++] = bt_test_args.le_phy;
		r_hci_command[r_hci_command_len++] = bt_test_args.mod_idx;
    } else if (bt_test_args.cmd == tx_tone){
		r_hci_command[r_hci_command_len++] = 0x01;
		r_hci_command[r_hci_command_len++] = 0x0D;
		r_hci_command[r_hci_command_len++] = 0x18;
		r_hci_command[r_hci_command_len++] = 0x06;
		r_hci_command[r_hci_command_len++] = bt_test_args.channel;
		r_hci_command[r_hci_command_len++] = (bt_test_args.tx_pwr & 0x0F);;
		r_hci_command[r_hci_command_len++] = 0x00;
		r_hci_command[r_hci_command_len++] = 0x00;
		r_hci_command[r_hci_command_len++] = 0x00;
		r_hci_command[r_hci_command_len++] = 0x00;
	} else if (bt_test_args.cmd == dut_dis_scan){
		r_hci_command[r_hci_command_len++] = 0x01;
		r_hci_command[r_hci_command_len++] = 0x1A;
		r_hci_command[r_hci_command_len++] = 0x0C;
		r_hci_command[r_hci_command_len++] = 0x01;
		r_hci_command[r_hci_command_len++] = 0x00;
	} else if (bt_test_args.cmd == get_txpwr){
		r_hci_command[r_hci_command_len++] = 0x01;
		r_hci_command[r_hci_command_len++] = 0x67;
		r_hci_command[r_hci_command_len++] = 0xFC;
		r_hci_command[r_hci_command_len++] = 0x01;
		r_hci_command[r_hci_command_len++] = 0x00;
	} else if (bt_test_args.cmd == set_txpwr){
		r_hci_command[r_hci_command_len++] = 0x01;
		r_hci_command[r_hci_command_len++] = 0x65;
		r_hci_command[r_hci_command_len++] = 0xFC;
		r_hci_command[r_hci_command_len++] = 0x02;
		r_hci_command[r_hci_command_len++] = bt_test_args.tx_pwr;
		r_hci_command[r_hci_command_len++] = 0x00;
	} else if (bt_test_args.cmd == set_pwrofst){
		r_hci_command[r_hci_command_len++] = 0x01;
		r_hci_command[r_hci_command_len++] = 0x72;
		r_hci_command[r_hci_command_len++] = 0xFC;
		r_hci_command[r_hci_command_len++] = 0x24;
		r_hci_command[r_hci_command_len++] = 0x27;
		r_hci_command[r_hci_command_len++] = 0x00;
		r_hci_command[r_hci_command_len++] = 0x02;
		r_hci_command[r_hci_command_len++] = 0x00;
		r_hci_command[r_hci_command_len++] = 0x01;
		r_hci_command[r_hci_command_len++] = (uint8_t)bt_test_args.tx_pwrofst;
		r_hci_command_len = 0x24 + 4;//payload len + hdr len
	}

	send_to_server(r_hci_command, r_hci_command_len);
}

void send_wlan_command(void)
{
    int i = 0;
    int command_len = 0;
    unsigned char buffer[SOCKER_BUFFER_SIZE] = {0,};
    while ((w_command[i] != NULL) && (i < WLAN_CMD_MAX_CNT)) {
        strcat((char*)&buffer[0], w_command[i]);
        strcat((char*)&buffer[0], " ");
        i++;
    }
    command_len = strlen((char*)&buffer[0]);
    printf("command_len:%d \r\n", command_len);
    if (command_len > 1) {
        //command_len--; // rm last space
        //buffer[command_len] = '\0';
        send_to_server(buffer, command_len);
    }
}

int hci_send(char* data, int len){
    int i = 0;
    unsigned char tmp_data[len];

    printf("COMMAND(%d): \r\n", len);
    for(i = 0; i < len; i++){
        tmp_data[i] = (unsigned char)data[i];
        printf("%02X ", tmp_data[i]);
    }
    printf("\r\n");

    len = write(bt_dev_fd, tmp_data, len);
    if (len < 0) {
        printf("write data error \n");
        return FALSE;
    }
    return TRUE;
}


int hci_recv(char* data, int len){
    int i = 0;
    unsigned char tmp_byte[64];// = 0x00;

    memset(data, 0, len);

    len = read(bt_dev_fd, data, len);
    if (len < 0) {
        printf("read error \n");
        return FALSE;
    }
    printf("EVENT(%d): \r\n", len);
    for(i = 0; i < len; i++){
        tmp_byte[i] = (unsigned char)data[i];
        printf("%02X ", tmp_byte[i]);
    }
    printf("\r\n");

    if(tmp_byte[1] == 0x0D) { //bt rx
        uint32_t rx_pkt_len = tmp_byte[4] | (tmp_byte[5] << 8) | (tmp_byte[6] << 16) | (tmp_byte[7] << 24);
        uint32_t sync_ok = tmp_byte[8] | (tmp_byte[9] << 8) | (tmp_byte[10] << 16) | (tmp_byte[11] << 24);
        uint32_t pkt_rx_ok = tmp_byte[12] | (tmp_byte[13] << 8) | (tmp_byte[14] << 16) | (tmp_byte[15] << 24);
        uint32_t rx_err_pkts = tmp_byte[16] | (tmp_byte[17] << 8) | (tmp_byte[18] << 16) | (tmp_byte[19] << 24);
        uint32_t bit_err = tmp_byte[20] | (tmp_byte[21] << 8) | (tmp_byte[22] << 16) | (tmp_byte[23] << 24);
        uint32_t bit_cnt = sync_ok * rx_pkt_len * 8;
        float per = (float) 100 * rx_err_pkts / sync_ok;
        float ber = (float) 100 * bit_err / bit_cnt;
        printf("bt_rx_result: rx_ok = %d, per = %.2f%%, ber = %.3f%%\n", pkt_rx_ok, per, ber);
    }
    if(tmp_byte[4] == 0x1F && tmp_byte[5] == 0x20) { //ble rx
        uint32_t pkt_rx_ok = (tmp_byte[8] << 8) | tmp_byte[7];
        printf("ble_rx_result: rx_ok = %d\n", pkt_rx_ok);
    }
    if(tmp_byte[1] == 0x0E && tmp_byte[4] == 0x67) { //get txpwr
        int8_t pwr_in_dbm = tmp_byte[7];
        uint8_t pwr_lvl = tmp_byte[8];
        printf("tx pwr: pwr_in_dbm = %d dBm, pwr_lvl = 0x%x\n", pwr_in_dbm, pwr_lvl);
    }

    return len;
}

int wlan_send(char *data, int len)
{
    int sock;
    struct ifreq ifr;
    int ret = 0;
    int i = 0;
    char wl_cmd[64];
    struct android_wifi_priv_cmd priv_cmd;
    char is_param_err = 0;
    int buf_len = 0;
    int argC = 0;

    sock = socket(PF_INET, SOCK_DGRAM, 0);
    if (sock < 0) {
        printf("bad sock!\n");
        return ERR;
    }

    memset(&ifr, 0, sizeof(ifr));
    strcpy(ifr.ifr_name, w_ifname);

    if (ioctl(sock, SIOCGIFFLAGS, &ifr) != 0) {
        printf("%s Could not read interface %s flags: %s",__func__, w_ifname, strerror(errno));
        return ERR;
    }

    if (!(ifr.ifr_flags & IFF_UP)) {
        printf("%s is not up!\n",w_ifname);
        return ERR;
    }

    printf("ifr.ifr_name = %s\n", ifr.ifr_name);
    memset(&priv_cmd, 0, sizeof(priv_cmd));
    memset(wl_cmd, 0, sizeof(wl_cmd));
    // extract wlan command & argC
    for (i = 0; i < len; i++) {
        if (data[i] != ' ') {
            if (argC == 0) {
                wl_cmd[i] = data[i];
            }
        } else {
            argC++;
        }
    }
    printf("wl_cmd=%s, argC=%d\r\n", wl_cmd, argC);

    priv_cmd.buf = data;
    priv_cmd.used_len = len;
    priv_cmd.total_len = SOCKER_BUFFER_SIZE;
    ifr.ifr_data = (void*)&priv_cmd;

    if ((strcasecmp(wl_cmd, "BT_RESET") == 0)) {
        char bt_reset_hci_cmd[32] = "01 03 0c 00";
        if (argC == 1) {
            buf_len = priv_cmd.used_len;
            memcpy(&priv_cmd.buf[buf_len], &bt_reset_hci_cmd[0], strlen(bt_reset_hci_cmd));
            buf_len += strlen(bt_reset_hci_cmd);
            priv_cmd.used_len = buf_len;
        } else {
            is_param_err = 1;
        }
    } else if ((strcasecmp(wl_cmd, "BT_TXDH") == 0)) {
        char bt_txdh_hci_cmd[255] = "01 06 18 0e ";
        if (argC == 15) {
            buf_len = priv_cmd.used_len;
            int arg_len = strlen("BT_TXDH");
            int txdh_cmd_len = strlen(bt_txdh_hci_cmd);
            memcpy(&bt_txdh_hci_cmd[txdh_cmd_len], &priv_cmd.buf[arg_len+1], buf_len - arg_len - 1);
            memcpy(&priv_cmd.buf[arg_len+1], &bt_txdh_hci_cmd[0], strlen(bt_txdh_hci_cmd));
            buf_len += strlen(bt_txdh_hci_cmd);
            priv_cmd.used_len = buf_len;
        } else {
            is_param_err = 1;
        }
    } else if ((strcasecmp(wl_cmd, "BT_RXDH") == 0)) {
        if (argC == 14) {
            char bt_rxdh_hci_cmd[255] = "01 0b 18 0d ";
            buf_len = priv_cmd.used_len;
            int arg_len = strlen("BT_RXDH");
            int rxdh_cmd_len = strlen(bt_rxdh_hci_cmd);
            memcpy(&bt_rxdh_hci_cmd[rxdh_cmd_len], &priv_cmd.buf[arg_len+1], buf_len - arg_len - 1);
            memcpy(&priv_cmd.buf[arg_len+1], &bt_rxdh_hci_cmd[0], strlen(bt_rxdh_hci_cmd));
            buf_len += strlen(bt_rxdh_hci_cmd);
            priv_cmd.used_len = buf_len;
        } else {
            is_param_err = 1;
        }
    }  else if ((strcasecmp(wl_cmd, "BT_STOP") == 0)) {
        char bt_stop_hci_cmd[255] = "01 0C 18 01 ";
        if (argC == 2) {
            buf_len = priv_cmd.used_len;
            int arg_len = strlen("BT_STOP");
            int stop_cmd_len = strlen(bt_stop_hci_cmd);
            memcpy(&bt_stop_hci_cmd[stop_cmd_len], &priv_cmd.buf[arg_len+1], buf_len - arg_len - 1);
            memcpy(&priv_cmd.buf[arg_len+1], &bt_stop_hci_cmd[0], strlen(bt_stop_hci_cmd));
            buf_len += strlen(bt_stop_hci_cmd);
            priv_cmd.used_len = buf_len;
    } else if ((strcasecmp(wl_cmd, "BT_DATA") == 0)) {
            //char bt_raw_data_cmd[255];
            int arg_len = strlen(wl_cmd);
            buf_len = priv_cmd.used_len;
            memcpy(&priv_cmd.buf[arg_len+1], &priv_cmd.buf[arg_len+1], buf_len - arg_len - 1);
            priv_cmd.used_len = buf_len - arg_len - 1;
    } else {
            is_param_err = 1;
        }
    } else {
        is_param_err = 0;
    }
    if (is_param_err) {
        printf("param error!!!\n");
        return ERR;
    }
    if ((ret = ioctl(sock, TXRX_PARA, &ifr)) < 0) {
        printf("%s: error ioctl[TX_PARA] ret= %d\n", __func__, ret);
        return ret;
    }
    memcpy(&priv_cmd, ifr.ifr_data, sizeof(struct android_wifi_priv_cmd));
    if (strcasecmp(wl_cmd, "GET_BT_RX_RESULT") == 0) {
        printf("done: get bt rx total=%d, ok=%d, err=%d\n", *(unsigned int *)priv_cmd.buf,
            *(unsigned int *)&priv_cmd.buf[4],
            *(unsigned int *)&priv_cmd.buf[8]);
    } else if (strcasecmp(wl_cmd, "BT_DATA") == 0) {
        unsigned char *buff = (unsigned char *)&priv_cmd.buf[1];
        int  len = priv_cmd.buf[0];
	int idx = 0;
        printf("done: %d\n", len);
        for (idx = 0; idx < len; idx++) {
            printf("%02x ", buff[idx]);
        }
        printf("\n");
     } else {
        printf("done\n");
    }
    return OK;
}

int dev_open(){
    int n = 0;

    bt_dev_fd = open(dev_path, O_RDWR | O_NDELAY);
    if(bt_dev_fd < 0) {
        printf("dev_path %s fail to open \r\n", dev_path);
        return ERR;
    }
    if(interface == UART){
        tcflush(bt_dev_fd, TCIOFLUSH);
        n = fcntl(bt_dev_fd, F_GETFL, 0);
        fcntl(bt_dev_fd, F_SETFL, n & ~O_NDELAY);
        uart_set_options(/*BAUDRATE*/atoi(s_baudrate), DATABITS, PARTY, STOP, SOFTWARE_HANDSHAKE, HARDWARE_HANDSHAKE);
    }else{
        ioctl(bt_dev_fd, DOWN_FW_CFG);
        ioctl(bt_dev_fd, GET_USB_INFO);
    }
    printf("bt dev open successful\r\n");
    return OK;
}

void dev_close(){
    close(bt_dev_fd);
}


int socket_init(){
    int client;
    int server_socket;
    struct sockaddr_in server_addr;
    struct sockaddr_in clientAddr;
    int addr_len = sizeof(clientAddr);
    char buffer[SOCKER_BUFFER_SIZE];
    int recv_len = 0;

    if((server_socket = socket(AF_INET, SOCK_STREAM, 0)) < 0){
        return ERR;
    }

    //bzero(&server_addr, sizeof(server_addr));
    memset(&server_addr, 0, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(BT_HCI_TOOL_PORT);
    server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    //setsockopt(server_socket ,SOL_SOCKET ,SO_REUSEADDR,(const char*)&bReuseaddr,sizeof(BOOL));

    if(bind(server_socket, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0){
        printf("binding error\r\n");
        return ERR;
    }

    if(listen(server_socket, 5) < 0){
        printf("listen error");
        return ERR;
    }

    while(1){
        client = accept(server_socket, (struct sockaddr*)&clientAddr, (socklen_t*)&addr_len);
        if(client == ERR){
            return 0;
        }
        recv_len = recv(client, buffer, SOCKER_BUFFER_SIZE, 0);
        if ((interface == USB) || (interface == UART)) {
            hci_send(buffer, recv_len);
        } else {
            wlan_send(buffer, recv_len);
        }
    }
}


void* hci_recv_thread( void *arg ){
    printf("hci recv thread ready %p\r\n", arg);
    while(1){
        hci_recv(hci_event, sizeof(hci_event));
//        exit(0);
    }
}

void start_server(){
    int ret = ERR;
    if ((interface == USB) || (interface == UART)) {
        pthread_t hci_recv_th;
        //init bt communication
        ret = dev_open();
        if(ret == ERR){
            printf("dev_open fail \r\n");
            return;
        }
        //test to send reset
        printf("to test hci reset for bt device\r\n");
        hci_send(hci_reset, sizeof(hci_reset));
        hci_recv(hci_event, sizeof(hci_event));
        ret = pthread_create( &hci_recv_th, NULL, hci_recv_thread, NULL);
        printf("bt device test ok \r\n");
    } else if (interface == WLAN) {
        char buf[SOCKER_BUFFER_SIZE] = {"BT_RESET "};
        wlan_send(buf, strlen(buf));
    }

        //init localhost socket
        ret = socket_init();
        if (!ret) {
            printf("socket init done\r\n");
        }
}

int main(int argc, char *argv[]){
	int ret = parse_cmd_line(argc, argv);
	if (ret) {
		return ret;
	}
	if(server_or_client == SERVER){
		start_server();
	} else if (server_or_client == CLIENT) {
		send_hci_command();
	} else if (server_or_client == CLIENT_DIRECT) {
		if (bt_test_args.cmd == ble_start) {
			send_to_server((unsigned char*)hci_reset, sizeof(hci_reset));
		} else if (bt_test_args.cmd == dut) {
			send_to_server((unsigned char*)hci_reset, sizeof(hci_reset));
			send_to_server((unsigned char*)set_filter, sizeof(set_filter));
			send_to_server((unsigned char*)scan_on, sizeof(scan_on));
			send_to_server((unsigned char*)dut_en, sizeof(dut_en));
			return 0;
		}
		send_raw_hci_command();
	} else {
		send_wlan_command();
	}
	return 0;
}
